package ginx

import (
	logger2 "booksmart/book/pkg/logger"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus"
	"net/http"
	"strconv"
)

var L logger2.LoggerV1

var vector *prometheus.CounterVec

func InitCounter(opt prometheus.CounterOpts) {
	vector = prometheus.NewCounterVec(opt,
		[]string{"code"})
	prometheus.MustRegister(vector)
	// 你可以考虑使用 code, method, 命中路由，HTTP 状态码
}

func Wrap(fn func(ctx *gin.Context) (Status, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		res, err := fn(ctx)
		if err != nil {
			// 开始处理 error，其实就是记录一下日志
			L.Error("处理业务逻辑出错",
				logger2.String("path", ctx.Request.URL.Path),
				// 命中的路由
				logger2.String("route", ctx.FullPath()),
				logger2.Error(err))
		}
		vector.WithLabelValues(strconv.Itoa(res.Code)).Inc()
		ctx.JSON(http.StatusOK, res)
	}
}

func WrapBodyAndToken[T any, S any](fn func(ctx *gin.Context, req T, authorInfo S) (Status, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var req T
		if err := ctx.Bind(&req); err != nil {
			return
		}
		author, ok := ctx.Get("author")
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
		}
		authorInfo, ok := author.(S)
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
		}
		res, err := fn(ctx, req, authorInfo)
		if err != nil {
			path := ctx.FullPath()
			L.Error("业务逻辑处理失败", logger2.String("method path", path), logger2.Error(err))
		}
		ctx.JSON(http.StatusOK, res)
	}
}

func WrapToken[T any](fn func(ctx *gin.Context, authorInfo T) (Status, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		author, ok := ctx.Get("author")
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
		}
		authorInfo, ok := author.(T)
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
		}
		res, err := fn(ctx, authorInfo)
		if err != nil {
			path := ctx.FullPath()
			L.Error("业务逻辑处理失败", logger2.String("method path", path), logger2.Error(err))
		}
		ctx.JSON(http.StatusOK, res)
	}
}

func WrapBody[T any](fn func(ctx *gin.Context, req T) (Status, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var req T
		if err := ctx.Bind(&req); err != nil {
			return
		}
		res, err := fn(ctx, req)
		if err != nil {
			path := ctx.FullPath()
			L.Error("业务逻辑处理失败", logger2.String("method path", path), logger2.Error(err))
		}
		ctx.JSON(http.StatusOK, res)
	}
}

type Status struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Date any    `json:"date"`
	Data any    `json:"data"`
}
